#ifndef _WX_DATETIME_H
#define _WX_DATETIME_H

#include "wx/defs.h"
#include <time.h>
#include <limits.h>
#include "wx/longlong.h"

class wxDateTime;
class wxTimeSpan;
class wxDateSpan;

#include "wx/dynarray.h"

#if defined(__WXMAC__) && !defined(__DARWIN__) && __MSL__ < 0x6000
#define WX_TIME_BASE_OFFSET ( 2082844800L + 126144000L )
#else
#define WX_TIME_BASE_OFFSET 0
#endif


/* Two wrapper functions for thread safety */
#ifdef HAVE_LOCALTIME_R
#define wxLocaltime_r localtime_r
#else
struct tm *wxLocaltime_r( const time_t*, struct tm* );
#if wxUSE_THREADS && !defined(__WINDOWS__) && !defined(__WATCOMC__)

#warning using pseudo thread-safe wrapper for localtime to emulate localtime_r
#endif
#endif

#ifdef HAVE_GMTIME_R
#define wxGmtime_r gmtime_r
#else
struct tm *wxGmtime_r( const time_t*, struct tm* );
#if wxUSE_THREADS && !defined(__WINDOWS__) && !defined(__WATCOMC__)

#warning using pseudo thread-safe wrapper for gmtime to emulate gmtime_r
#endif
#endif

class wxDateTime;

extern const wxChar* wxDefaultDateTimeFormat;
extern const wxChar* wxDefaultTimeSpanFormat;
extern const wxDateTime wxDefaultDateTime;

#define wxInvalidDateTime wxDefaultDateTime

class wxDateTime {
  public:
    typedef unsigned short wxDateTime_t;
    enum TZ {

      Local,
      GMT_12, GMT_11, GMT_10, GMT_9, GMT_8, GMT_7,
      GMT_6, GMT_5, GMT_4, GMT_3, GMT_2, GMT_1,
      GMT0,
      GMT1, GMT2, GMT3, GMT4, GMT5, GMT6,
      GMT7, GMT8, GMT9, GMT10, GMT11, GMT12, GMT13,
      WET = GMT0,
      WEST = GMT1,
      CET = GMT1,
      CEST = GMT2,
      EET = GMT2,
      EEST = GMT3,
      MSK = GMT3,
      MSD = GMT4,
      AST = GMT_4,
      ADT = GMT_3,
      EST = GMT_5,
      EDT = GMT_4,
      CST = GMT_6,
      CDT = GMT_5,
      MST = GMT_7,
      MDT = GMT_6,
      PST = GMT_8,
      PDT = GMT_7,
      HST = GMT_10,
      AKST = GMT_9,
      AKDT = GMT_8,

      A_WST = GMT8,
      A_CST = GMT13 + 1,
      A_EST = GMT10,
      A_ESST = GMT11,
      NZST = GMT12,
      NZDT = GMT13,

      UTC = GMT0
    };

    enum Calendar {
      Gregorian,
      Julian

    };

    enum GregorianAdoption {
      Gr_Unknown,
      Gr_Standard,

      Gr_Alaska,
      Gr_Albania,

      Gr_Austria = Gr_Unknown,
      Gr_Austria_Brixen,
      Gr_Austria_Salzburg = Gr_Austria_Brixen,
      Gr_Austria_Tyrol = Gr_Austria_Brixen,
      Gr_Austria_Carinthia,
      Gr_Austria_Styria = Gr_Austria_Carinthia,

      Gr_Belgium,

      Gr_Bulgaria = Gr_Unknown,
      Gr_Bulgaria_1,
      Gr_Bulgaria_2,
      Gr_Bulgaria_3,

      Gr_Canada = Gr_Unknown,
      Gr_China = Gr_Unknown,
      Gr_China_1,
      Gr_China_2,

      Gr_Czechoslovakia,
      Gr_Denmark,
      Gr_Egypt,
      Gr_Estonia,
      Gr_Finland,

      Gr_France,
      Gr_France_Alsace,
      Gr_France_Lorraine,
      Gr_France_Strasbourg,

      Gr_Germany = Gr_Unknown,
      Gr_Germany_Catholic,
      Gr_Germany_Prussia,
      Gr_Germany_Protestant,

      Gr_GreatBritain,

      Gr_Greece,
      Gr_Hungary,
      Gr_Ireland = Gr_GreatBritain,
      Gr_Italy = Gr_Standard,

      Gr_Japan = Gr_Unknown,
      Gr_Japan_1,
      Gr_Japan_2,
      Gr_Japan_3,

      Gr_Latvia,
      Gr_Lithuania,
      Gr_Luxemburg,
      Gr_Netherlands = Gr_Belgium,
      Gr_Netherlands_Groningen,
      Gr_Netherlands_Gelderland,
      Gr_Netherlands_Utrecht,
      Gr_Netherlands_Friesland,

      Gr_Norway = Gr_Denmark,
      Gr_Poland = Gr_Standard,
      Gr_Portugal = Gr_Standard,
      Gr_Romania,
      Gr_Russia,
      Gr_Scotland = Gr_GreatBritain,
      Gr_Spain = Gr_Standard,
      Gr_Sweden = Gr_Finland,
      Gr_Switzerland = Gr_Unknown,
      Gr_Switzerland_Catholic,
      Gr_Switzerland_Protestant,

      Gr_Turkey,
      Gr_USA = Gr_GreatBritain,
      Gr_Wales = Gr_GreatBritain,
      Gr_Yugoslavia
    };

    #ifdef USA
#undef USA
    #endif

    enum Country {
      Country_Unknown,
      Country_Default,
      Country_WesternEurope_Start,
      Country_EEC = Country_WesternEurope_Start,
      France,
      Germany,
      UK,
      Country_WesternEurope_End = UK,

      Russia,
      USA
    };

    enum Month {
      Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec, Inv_Month
    };
    enum WeekDay {
      Sun, Mon, Tue, Wed, Thu, Fri, Sat, Inv_WeekDay
    };
    enum Year {
      Inv_Year = SHRT_MIN
    };
    enum NameFlags {
      Name_Full = 0x01,
      Name_Abbr = 0x02
    };
    enum WeekFlags {
      Default_First,
      Monday_First,
      Sunday_First
    };

    class TimeZone {
      public:
        TimeZone( TZ tz );
        TimeZone( wxDateTime_t offset = 0 ) { m_offset = offset; }
        static TimeZone Make( long offset ) {
          TimeZone tz;
          tz.m_offset = offset;
          return tz;
        }
        long GetOffset() const { return m_offset; }

      private:

        long m_offset;
    };

    struct Tm {
        wxDateTime_t msec, sec, min, hour, mday;
        Month mon;
        int year;
        Tm();
        Tm( const struct tm& tm, const TimeZone& tz );
        bool IsValid() const;
        WeekDay GetWeekDay() {
          if( wday == Inv_WeekDay ) {
            ComputeWeekDay();
          }
          return ( WeekDay )wday;
        }
        void AddMonths( int monDiff );
        void AddDays( int dayDiff );

      private:

        void ComputeWeekDay();
        TimeZone m_tz;

        wxDateTime_t wday, yday;
    };

    static void SetCountry( Country country );

    static Country GetCountry();

    static bool IsWestEuropeanCountry( Country country = Country_Default );
    static int GetCurrentYear( Calendar cal = Gregorian );

    static int ConvertYearToBC( int year );
    static Month GetCurrentMonth( Calendar cal = Gregorian );
    static bool IsLeapYear( int year = Inv_Year, Calendar cal = Gregorian );
    static int GetCentury( int year );

    static wxDateTime_t GetNumberOfDays( int year, Calendar cal = Gregorian );

    static wxDateTime_t GetNumberOfDays( Month month, int year = Inv_Year, Calendar cal = Gregorian );

    static wxString GetMonthName( Month month, NameFlags flags = Name_Full );

    static wxString GetWeekDayName( WeekDay weekday, NameFlags flags = Name_Full );
    static void GetAmPmStrings( wxString *am, wxString *pm );
    static bool IsDSTApplicable( int year = Inv_Year, Country country = Country_Default );
    static wxDateTime GetBeginDST( int year = Inv_Year, Country country = Country_Default );

    static wxDateTime GetEndDST( int year = Inv_Year, Country country = Country_Default );
    static inline wxDateTime Now();

    static wxDateTime UNow();

    static inline wxDateTime Today();
    wxDateTime() { m_time = wxLongLong( ( wxInt32 )UINT_MAX, UINT_MAX ); }
    #if (!(defined(__VISAGECPP__) && __IBMCPP__ >= 400))

    inline wxDateTime( time_t timet );
    #endif

    inline wxDateTime( const struct tm& tm );

    inline wxDateTime( const Tm& tm );
    inline wxDateTime( double jdn );
    inline wxDateTime( wxDateTime_t hour,
                       wxDateTime_t minute = 0,
                       wxDateTime_t second = 0,
                       wxDateTime_t millisec = 0 );

    inline wxDateTime( wxDateTime_t day,
                       Month        month,
                       int          year = Inv_Year,
                       wxDateTime_t hour = 0,
                       wxDateTime_t minute = 0,
                       wxDateTime_t second = 0,
                       wxDateTime_t millisec = 0 );

    inline wxDateTime& SetToCurrent();

    #if (!(defined(__VISAGECPP__) && __IBMCPP__ >= 400))
    inline wxDateTime& Set( time_t timet );
    #endif
    wxDateTime& Set( const struct tm& tm );
    inline wxDateTime& Set( const Tm& tm );
    wxDateTime& Set( double jdn );
    wxDateTime& Set( wxDateTime_t hour,
                     wxDateTime_t minute = 0,
                     wxDateTime_t second = 0,
                     wxDateTime_t millisec = 0 );

    wxDateTime& Set( wxDateTime_t day,
                     Month        month,
                     int          year = Inv_Year,
                     wxDateTime_t hour = 0,
                     wxDateTime_t minute = 0,
                     wxDateTime_t second = 0,
                     wxDateTime_t millisec = 0 );
    wxDateTime& ResetTime();
    wxDateTime GetDateOnly() const;
    wxDateTime& SetYear( int year );
    wxDateTime& SetMonth( Month month );

    wxDateTime& SetDay( wxDateTime_t day );

    wxDateTime& SetHour( wxDateTime_t hour );

    wxDateTime& SetMinute( wxDateTime_t minute );

    wxDateTime& SetSecond( wxDateTime_t second );

    wxDateTime& SetMillisecond( wxDateTime_t millisecond );
    wxDateTime& operator=( time_t timet ) { return Set( timet ); }
    wxDateTime& operator=( const struct tm& tm ) { return Set( tm ); }
    wxDateTime& operator=( const Tm& tm ) { return Set( tm ); }

    wxDateTime& SetToWeekDayInSameWeek( WeekDay weekday, WeekFlags flags = Monday_First );
    inline wxDateTime GetWeekDayInSameWeek( WeekDay weekday, WeekFlags flags = Monday_First ) const;
    wxDateTime& SetToNextWeekDay( WeekDay weekday );
    inline wxDateTime GetNextWeekDay( WeekDay weekday ) const;
    wxDateTime& SetToPrevWeekDay( WeekDay weekday );
    inline wxDateTime GetPrevWeekDay( WeekDay weekday ) const;

    bool SetToWeekDay( WeekDay weekday,
                       int n = 1,
                       Month month = Inv_Month,
                       int year = Inv_Year );
    inline wxDateTime GetWeekDay( WeekDay weekday,
                                  int n = 1,
                                  Month month = Inv_Month,
                                  int year = Inv_Year ) const;
    inline bool SetToLastWeekDay( WeekDay weekday,
                                  Month month = Inv_Month,
                                  int year = Inv_Year );
    inline wxDateTime GetLastWeekDay( WeekDay weekday,
                                      Month month = Inv_Month,
                                      int year = Inv_Year );
    wxDEPRECATED( bool SetToTheWeek( wxDateTime_t numWeek,
                                     WeekDay weekday = Mon,
                                     WeekFlags flags = Monday_First ) );
    wxDEPRECATED( wxDateTime GetWeek( wxDateTime_t numWeek,
                                      WeekDay weekday = Mon,
                                      WeekFlags flags = Monday_First ) const );
    static wxDateTime SetToWeekOfYear( int year,
                                       wxDateTime_t numWeek,
                                       WeekDay weekday = Mon );

    wxDateTime& SetToLastMonthDay( Month month = Inv_Month,
                                   int year = Inv_Year );
    inline wxDateTime GetLastMonthDay( Month month = Inv_Month,
                                       int year = Inv_Year ) const;
    wxDateTime& SetToYearDay( wxDateTime_t yday );
    inline wxDateTime GetYearDay( wxDateTime_t yday ) const;

    double GetJulianDayNumber() const;
    double GetJDN() const { return GetJulianDayNumber(); }
    double GetModifiedJulianDayNumber() const { return GetJDN() - 2400000.5; }
    double GetMJD() const { return GetModifiedJulianDayNumber(); }
    double GetRataDie() const;
    inline wxDateTime ToTimezone( const TimeZone& tz, bool noDST = false ) const;
    wxDateTime& MakeTimezone( const TimeZone& tz, bool noDST = false );

    inline wxDateTime FromTimezone( const TimeZone& tz, bool noDST = false ) const;
    wxDateTime& MakeFromTimezone( const TimeZone& tz, bool noDST = false );
    wxDateTime ToUTC( bool noDST = false ) const { return ToTimezone( UTC, noDST ); }
    wxDateTime& MakeUTC( bool noDST = false ) { return MakeTimezone( UTC, noDST ); }

    wxDateTime ToGMT( bool noDST = false ) const { return ToUTC( noDST ); }
    wxDateTime& MakeGMT( bool noDST = false ) { return MakeUTC( noDST ); }

    wxDateTime FromUTC( bool noDST = false ) const
    { return FromTimezone( UTC, noDST ); }
    wxDateTime& MakeFromUTC( bool noDST = false ) { return MakeFromTimezone( UTC, noDST ); }
    int IsDST( Country country = Country_Default ) const;
    inline bool IsValid() const { return m_time != wxInvalidDateTime.m_time; }
    Tm GetTm( const TimeZone& tz = Local ) const;

    inline time_t GetTicks() const;
    int GetCentury( const TimeZone& tz = Local ) const
    { return GetCentury( GetYear( tz ) ); }

    int GetYear( const TimeZone& tz = Local ) const
    { return GetTm( tz ).year; }

    Month GetMonth( const TimeZone& tz = Local ) const
    { return ( Month )GetTm( tz ).mon; }

    wxDateTime_t GetDay( const TimeZone& tz = Local ) const
    { return GetTm( tz ).mday; }

    WeekDay GetWeekDay( const TimeZone& tz = Local ) const
    { return GetTm( tz ).GetWeekDay(); }

    wxDateTime_t GetHour( const TimeZone& tz = Local ) const
    { return GetTm( tz ).hour; }

    wxDateTime_t GetMinute( const TimeZone& tz = Local ) const
    { return GetTm( tz ).min; }

    wxDateTime_t GetSecond( const TimeZone& tz = Local ) const
    { return GetTm( tz ).sec; }

    wxDateTime_t GetMillisecond( const TimeZone& tz = Local ) const
    { return GetTm( tz ).msec; }
    wxDateTime_t GetDayOfYear( const TimeZone& tz = Local ) const;
    wxDateTime_t GetWeekOfYear( WeekFlags flags = Monday_First,
                                const TimeZone& tz = Local ) const;
    wxDateTime_t GetWeekOfMonth( WeekFlags flags = Monday_First,
                                 const TimeZone& tz = Local ) const;

    bool IsWorkDay( Country country = Country_Default ) const;

    bool IsGregorianDate( GregorianAdoption country = Gr_Standard ) const;

    wxDateTime& SetFromDOS( unsigned long ddt );
    unsigned long GetAsDOS() const;

    inline bool IsEqualTo( const wxDateTime& datetime ) const;
    inline bool IsEarlierThan( const wxDateTime& datetime ) const;
    inline bool IsLaterThan( const wxDateTime& datetime ) const;
    inline bool IsStrictlyBetween( const wxDateTime& t1,
                                   const wxDateTime& t2 ) const;
    inline bool IsBetween( const wxDateTime& t1, const wxDateTime& t2 ) const;
    inline bool IsSameDate( const wxDateTime& dt ) const;
    inline bool IsSameTime( const wxDateTime& dt ) const;
    inline bool IsEqualUpTo( const wxDateTime& dt, const wxTimeSpan& ts ) const;

    inline bool operator<( const wxDateTime& dt ) const {
      wxASSERT_MSG( IsValid() && dt.IsValid(), wxT( "invalid wxDateTime" ) );
      return GetValue() < dt.GetValue();
    }

    inline bool operator<=( const wxDateTime& dt ) const {
      wxASSERT_MSG( IsValid() && dt.IsValid(), wxT( "invalid wxDateTime" ) );
      return GetValue() <= dt.GetValue();
    }

    inline bool operator>( const wxDateTime& dt ) const {
      wxASSERT_MSG( IsValid() && dt.IsValid(), wxT( "invalid wxDateTime" ) );
      return GetValue() > dt.GetValue();
    }

    inline bool operator>=( const wxDateTime& dt ) const {
      wxASSERT_MSG( IsValid() && dt.IsValid(), wxT( "invalid wxDateTime" ) );
      return GetValue() >= dt.GetValue();
    }

    inline bool operator==( const wxDateTime& dt ) const {
      wxASSERT_MSG( IsValid() && dt.IsValid(), wxT( "invalid wxDateTime" ) );
      return GetValue() == dt.GetValue();
    }

    inline bool operator!=( const wxDateTime& dt ) const {
      wxASSERT_MSG( IsValid() && dt.IsValid(), wxT( "invalid wxDateTime" ) );
      return GetValue() != dt.GetValue();
    }

    inline wxDateTime Add( const wxTimeSpan& diff ) const;

    inline wxDateTime& Add( const wxTimeSpan& diff );

    inline wxDateTime& operator+=( const wxTimeSpan& diff );
    inline wxDateTime operator+( const wxTimeSpan& ts ) const {
      wxDateTime dt( *this );
      dt.Add( ts );
      return dt;
    }
    inline wxDateTime Subtract( const wxTimeSpan& diff ) const;

    inline wxDateTime& Subtract( const wxTimeSpan& diff );

    inline wxDateTime& operator-=( const wxTimeSpan& diff );
    inline wxDateTime operator-( const wxTimeSpan& ts ) const {
      wxDateTime dt( *this );
      dt.Subtract( ts );
      return dt;
    }
    inline wxDateTime Add( const wxDateSpan& diff ) const;

    wxDateTime& Add( const wxDateSpan& diff );

    inline wxDateTime& operator+=( const wxDateSpan& diff );
    inline wxDateTime operator+( const wxDateSpan& ds ) const {
      wxDateTime dt( *this );
      dt.Add( ds );
      return dt;
    }
    inline wxDateTime Subtract( const wxDateSpan& diff ) const;

    inline wxDateTime& Subtract( const wxDateSpan& diff );

    inline wxDateTime& operator-=( const wxDateSpan& diff );
    inline wxDateTime operator-( const wxDateSpan& ds ) const {
      wxDateTime dt( *this );
      dt.Subtract( ds );
      return dt;
    }
    inline wxTimeSpan Subtract( const wxDateTime& dt ) const;
    inline wxTimeSpan operator-( const wxDateTime& dt2 ) const;
    const wxChar *ParseRfc822Date( const wxChar* date );
    const wxChar *ParseFormat( const wxChar *date,
                               const wxChar *format = wxDefaultDateTimeFormat,
                               const wxDateTime& dateDef = wxDefaultDateTime );
    const wxChar *ParseDateTime( const wxChar *datetime );
    const wxChar *ParseDate( const wxChar *date );

    const wxChar *ParseTime( const wxChar *time );

    wxString Format( const wxChar *format = wxDefaultDateTimeFormat,
                     const TimeZone& tz = Local ) const;

    wxString FormatDate() const { return Format( wxT( "%x" ) ); }

    wxString FormatTime() const { return Format( wxT( "%X" ) ); }
    wxString FormatISODate() const { return Format( wxT( "%Y-%m-%d" ) ); }
    wxString FormatISOTime() const { return Format( wxT( "%H:%M:%S" ) ); }

    wxDateTime( const wxLongLong& time ) { m_time = time; }
    inline wxLongLong GetValue() const;
    static time_t GetTimeNow() { return time( ( time_t * )NULL ); }
    static struct tm *GetTmNow() {
      static struct tm l_CurrentTime;
      return GetTmNow( &l_CurrentTime );
    }
    static struct tm *GetTmNow( struct tm *tmstruct );

  private:
    static Country ms_country;
    static const long TIME_T_FACTOR;
    inline bool IsInStdRange() const;
    wxLongLong m_time;
};

class wxTimeSpan {
  public:
    static wxTimeSpan Milliseconds( wxLongLong ms ) { return wxTimeSpan( 0, 0, 0, ms ); }
    static wxTimeSpan Millisecond() { return Milliseconds( 1 ); }
    static wxTimeSpan Seconds( wxLongLong sec ) { return wxTimeSpan( 0, 0, sec ); }
    static wxTimeSpan Second() { return Seconds( 1 ); }
    static wxTimeSpan Minutes( long min ) { return wxTimeSpan( 0, min, 0 ); }
    static wxTimeSpan Minute() { return Minutes( 1 ); }
    static wxTimeSpan Hours( long hours ) { return wxTimeSpan( hours, 0, 0 ); }
    static wxTimeSpan Hour() { return Hours( 1 ); }
    static wxTimeSpan Days( long days ) { return Hours( 24 * days ); }
    static wxTimeSpan Day() { return Days( 1 ); }
    static wxTimeSpan Weeks( long days ) { return Days( 7 * days ); }
    static wxTimeSpan Week() { return Weeks( 1 ); }
    wxTimeSpan() { }
    inline wxTimeSpan( long hours, long minutes = 0, wxLongLong seconds = 0, wxLongLong milliseconds = 0 );
    inline wxTimeSpan Add( const wxTimeSpan& diff ) const;

    inline wxTimeSpan& Add( const wxTimeSpan& diff );

    wxTimeSpan& operator+=( const wxTimeSpan& diff ) { return Add( diff ); }
    inline wxTimeSpan operator+( const wxTimeSpan& ts ) const {
      return wxTimeSpan( GetValue() + ts.GetValue() );
    }
    inline wxTimeSpan Subtract( const wxTimeSpan& diff ) const;

    inline wxTimeSpan& Subtract( const wxTimeSpan& diff );

    wxTimeSpan& operator-=( const wxTimeSpan& diff ) { return Subtract( diff ); }
    inline wxTimeSpan operator-( const wxTimeSpan& ts ) {
      return wxTimeSpan( GetValue() - ts.GetValue() );
    }
    inline wxTimeSpan Multiply( int n ) const;

    inline wxTimeSpan& Multiply( int n );

    wxTimeSpan& operator*=( int n ) { return Multiply( n ); }
    inline wxTimeSpan operator*( int n ) const {
      return wxTimeSpan( *this ).Multiply( n );
    }
    wxTimeSpan Negate() const { return wxTimeSpan( -GetValue() ); }

    wxTimeSpan& Neg() { m_diff = -GetValue(); return *this; }

    wxTimeSpan& operator-() { return Neg(); }

    inline wxTimeSpan Abs() const;
    bool IsNull() const { return m_diff == 0l; }

    bool operator!() const { return !IsNull(); }
    bool IsPositive() const { return m_diff > 0l; }
    bool IsNegative() const { return m_diff < 0l; }
    inline bool IsEqualTo( const wxTimeSpan& ts ) const;
    inline bool IsLongerThan( const wxTimeSpan& ts ) const;
    bool IsShorterThan( const wxTimeSpan& t ) const { return !IsLongerThan( t ); }

    inline bool operator<( const wxTimeSpan &ts ) const {
      return GetValue() < ts.GetValue();
    }

    inline bool operator<=( const wxTimeSpan &ts ) const {
      return GetValue() <= ts.GetValue();
    }

    inline bool operator>( const wxTimeSpan &ts ) const {
      return GetValue() > ts.GetValue();
    }

    inline bool operator>=( const wxTimeSpan &ts ) const {
      return GetValue() >= ts.GetValue();
    }
    inline bool operator==( const wxTimeSpan &ts ) const {
      return GetValue() == ts.GetValue();
    }
    inline bool operator!=( const wxTimeSpan &ts ) const {
      return GetValue() != ts.GetValue();
    }
    inline int GetWeeks() const;
    inline int GetDays() const;
    inline int GetHours() const;
    inline int GetMinutes() const;
    inline wxLongLong GetSeconds() const;
    wxLongLong GetMilliseconds() const { return m_diff; }
    wxString Format( const wxChar *format = wxDefaultTimeSpanFormat ) const;
    wxTimeSpan( const wxLongLong& diff ) { m_diff = diff; }
    wxLongLong GetValue() const { return m_diff; }

  private:

    wxLongLong m_diff;
};

class wxDateSpan {
  public:
    wxDateSpan( int years = 0, int months = 0, int weeks = 0, int days = 0 ) {
      m_years = years;
      m_months = months;
      m_weeks = weeks;
      m_days = days;
    }
    static wxDateSpan Days( int days ) { return wxDateSpan( 0, 0, 0, days ); }
    static wxDateSpan Day() { return Days( 1 ); }
    static wxDateSpan Weeks( int weeks ) { return wxDateSpan( 0, 0, weeks, 0 ); }
    static wxDateSpan Week() { return Weeks( 1 ); }
    static wxDateSpan Months( int mon ) { return wxDateSpan( 0, mon, 0, 0 ); }
    static wxDateSpan Month() { return Months( 1 ); }
    static wxDateSpan Years( int years ) { return wxDateSpan( years, 0, 0, 0 ); }
    static wxDateSpan Year() { return Years( 1 ); }
    wxDateSpan& SetYears( int n ) { m_years = n; return *this; }
    wxDateSpan& SetMonths( int n ) { m_months = n; return *this; }
    wxDateSpan& SetWeeks( int n ) { m_weeks = n; return *this; }
    wxDateSpan& SetDays( int n ) { m_days = n; return *this; }
    int GetYears() const { return m_years; }
    int GetMonths() const { return m_months; }
    int GetWeeks() const { return m_weeks; }
    int GetDays() const { return m_days; }
    int GetTotalDays() const { return 7 * m_weeks + m_days; }
    inline wxDateSpan Add( const wxDateSpan& other ) const;
    inline wxDateSpan& Add( const wxDateSpan& other );
    inline wxDateSpan& operator+=( const wxDateSpan& other );
    inline wxDateSpan operator+( const wxDateSpan& ds ) const {
      return wxDateSpan( GetYears() + ds.GetYears(), GetMonths() + ds.GetMonths(),
                         GetWeeks() + ds.GetWeeks(), GetDays() + ds.GetDays() );
    }
    inline wxDateSpan Subtract( const wxDateSpan& other ) const;
    inline wxDateSpan& Subtract( const wxDateSpan& other );
    inline wxDateSpan& operator-=( const wxDateSpan& other );
    inline wxDateSpan operator-( const wxDateSpan& ds ) const {
      return wxDateSpan( GetYears() - ds.GetYears(), GetMonths() - ds.GetMonths(),
                         GetWeeks() - ds.GetWeeks(), GetDays() - ds.GetDays() );
    }
    inline wxDateSpan Negate() const;
    inline wxDateSpan& Neg();
    wxDateSpan& operator-() { return Neg(); }
    inline wxDateSpan Multiply( int factor ) const;
    inline wxDateSpan& Multiply( int factor );
    inline wxDateSpan& operator*=( int factor ) { return Multiply( factor ); }
    inline wxDateSpan operator*( int n ) const {
      return wxDateSpan( *this ).Multiply( n );
    }
    inline bool operator==( const wxDateSpan& ds ) const {
      return GetYears() == ds.GetYears() &&
             GetMonths() == ds.GetMonths() &&
             GetTotalDays() == ds.GetTotalDays();
    }
    inline bool operator!=( const wxDateSpan& ds ) const {
      return !( *this == ds );
    }
  private:
    int m_years, m_months, m_weeks, m_days;
};

WX_DECLARE_USER_EXPORTED_OBJARRAY( wxDateTime, wxDateTimeArray );

class wxDateTimeHolidayAuthority;
WX_DEFINE_USER_EXPORTED_ARRAY_PTR( wxDateTimeHolidayAuthority *, wxHolidayAuthoritiesArray );

class wxDateTimeHolidaysModule;
class wxDateTimeHolidayAuthority {
    friend class wxDateTimeHolidaysModule;
  public:
    static bool IsHoliday( const wxDateTime& dt );
    static size_t GetHolidaysInRange( const wxDateTime& dtStart, const wxDateTime& dtEnd,
                                      wxDateTimeArray& holidays );
    static void ClearAllAuthorities();
    static void AddAuthority( wxDateTimeHolidayAuthority *auth );
    virtual ~wxDateTimeHolidayAuthority();
  protected:
    virtual bool DoIsHoliday( const wxDateTime& dt ) const = 0;
    virtual size_t DoGetHolidaysInRange( const wxDateTime& dtStart, const wxDateTime& dtEnd,
                                         wxDateTimeArray& holidays ) const = 0;
  private:
    static wxHolidayAuthoritiesArray ms_authorities;
};


class wxDateTimeWorkDays : public wxDateTimeHolidayAuthority {
  protected:
    virtual bool DoIsHoliday( const wxDateTime& dt ) const;
    virtual size_t DoGetHolidaysInRange( const wxDateTime& dtStart, const wxDateTime& dtEnd,
                                         wxDateTimeArray& holidays ) const;
};

#define MILLISECONDS_PER_DAY 86400000l

#ifndef __HPUX__
#define MODIFY_AND_RETURN(op) return wxDateTime(*this).op
#else
#define MODIFY_AND_RETURN(op) wxDateTime dt(*this); dt.op; return dt
#endif

inline bool wxDateTime::IsInStdRange() const {
  return m_time >= 0l && ( m_time / TIME_T_FACTOR ) < LONG_MAX;
}

inline wxDateTime wxDateTime::Now() {
  struct tm tmstruct;
  return wxDateTime( *GetTmNow( &tmstruct ) );
}

inline wxDateTime wxDateTime::Today() {
  wxDateTime dt( Now() );
  dt.ResetTime();
  return dt;
}

#if (!(defined(__VISAGECPP__) && __IBMCPP__ >= 400))
inline wxDateTime& wxDateTime::Set( time_t timet ) {
  m_time = timet - WX_TIME_BASE_OFFSET ;
  m_time *= TIME_T_FACTOR;
  return *this;
}
#endif

inline wxDateTime& wxDateTime::SetToCurrent() {
  *this = Now();
  return *this;
}

#if (!(defined(__VISAGECPP__) && __IBMCPP__ >= 400))
inline wxDateTime::wxDateTime( time_t timet ) {
  Set( timet );
}
#endif

inline wxDateTime::wxDateTime( const struct tm& tm ) {
  Set( tm );
}

inline wxDateTime::wxDateTime( const Tm& tm ) {
  Set( tm );
}

inline wxDateTime::wxDateTime( double jdn ) {
  Set( jdn );
}

inline wxDateTime& wxDateTime::Set( const Tm& tm ) {
  wxASSERT_MSG( tm.IsValid(), wxT( "invalid broken down date/time" ) );
  return Set( tm.mday, ( Month )tm.mon, tm.year,
              tm.hour, tm.min, tm.sec, tm.msec );
}

inline wxDateTime::wxDateTime( wxDateTime_t hour,
                               wxDateTime_t minute,
                               wxDateTime_t second,
                               wxDateTime_t millisec ) {
  Set( hour, minute, second, millisec );
}

inline wxDateTime::wxDateTime( wxDateTime_t day,
                               Month        month,
                               int          year,
                               wxDateTime_t hour,
                               wxDateTime_t minute,
                               wxDateTime_t second,
                               wxDateTime_t millisec ) {
  Set( day, month, year, hour, minute, second, millisec );
}

inline wxLongLong wxDateTime::GetValue() const {
  wxASSERT_MSG( IsValid(), wxT( "invalid wxDateTime" ) );
  return m_time;
}

inline time_t wxDateTime::GetTicks() const {
  wxASSERT_MSG( IsValid(), wxT( "invalid wxDateTime" ) );
  if( !IsInStdRange() ) {
    return ( time_t ) - 1;
  }
  return ( time_t )( ( m_time / ( long )TIME_T_FACTOR ).ToLong() ) + WX_TIME_BASE_OFFSET;
}

inline bool wxDateTime::SetToLastWeekDay( WeekDay weekday,
    Month month,
    int year ) {
  return SetToWeekDay( weekday, -1, month, year );
}

inline wxDateTime
wxDateTime::GetWeekDayInSameWeek( WeekDay weekday, WeekFlags( flags ) ) const {
  MODIFY_AND_RETURN( SetToWeekDayInSameWeek( weekday ) );
}

inline wxDateTime wxDateTime::GetNextWeekDay( WeekDay weekday ) const {
  MODIFY_AND_RETURN( SetToNextWeekDay( weekday ) );
}

inline wxDateTime wxDateTime::GetPrevWeekDay( WeekDay weekday ) const {
  MODIFY_AND_RETURN( SetToPrevWeekDay( weekday ) );
}

inline wxDateTime wxDateTime::GetWeekDay( WeekDay weekday, int n, Month month, int year ) const {
  wxDateTime dt( *this );
  return dt.SetToWeekDay( weekday, n, month, year ) ? dt : wxInvalidDateTime;
}

inline wxDateTime wxDateTime::GetLastWeekDay( WeekDay weekday,
    Month month,
    int year ) {
  wxDateTime dt( *this );
  return dt.SetToLastWeekDay( weekday, month, year ) ? dt : wxInvalidDateTime;
}

inline wxDateTime wxDateTime::GetLastMonthDay( Month month, int year ) const {
  MODIFY_AND_RETURN( SetToLastMonthDay( month, year ) );
}

inline wxDateTime wxDateTime::GetYearDay( wxDateTime_t yday ) const {
  MODIFY_AND_RETURN( SetToYearDay( yday ) );
}

inline bool wxDateTime::IsEqualTo( const wxDateTime& datetime ) const {
  wxASSERT_MSG( IsValid() && datetime.IsValid(), wxT( "invalid wxDateTime" ) );
  return m_time == datetime.m_time;
}

inline bool wxDateTime::IsEarlierThan( const wxDateTime& datetime ) const {
  wxASSERT_MSG( IsValid() && datetime.IsValid(), wxT( "invalid wxDateTime" ) );
  return m_time < datetime.m_time;
}

inline bool wxDateTime::IsLaterThan( const wxDateTime& datetime ) const {
  wxASSERT_MSG( IsValid() && datetime.IsValid(), wxT( "invalid wxDateTime" ) );
  return m_time > datetime.m_time;
}

inline bool wxDateTime::IsStrictlyBetween( const wxDateTime& t1,
    const wxDateTime& t2 ) const {
  return IsLaterThan( t1 ) && IsEarlierThan( t2 );
}

inline bool wxDateTime::IsBetween( const wxDateTime& t1, const wxDateTime& t2 ) const {
  return IsEqualTo( t1 ) || IsEqualTo( t2 ) || IsStrictlyBetween( t1, t2 );
}

inline bool wxDateTime::IsSameDate( const wxDateTime& dt ) const {
  Tm tm1 = GetTm(), tm2 = dt.GetTm();
  return tm1.year == tm2.year &&
         tm1.mon == tm2.mon &&
         tm1.mday == tm2.mday;
}

inline bool wxDateTime::IsSameTime( const wxDateTime& dt ) const {
  Tm tm1 = GetTm(), tm2 = dt.GetTm();
  return tm1.hour == tm2.hour &&
         tm1.min == tm2.min &&
         tm1.sec == tm2.sec &&
         tm1.msec == tm2.msec;
}

inline bool wxDateTime::IsEqualUpTo( const wxDateTime& dt,
                                     const wxTimeSpan& ts ) const {
  return IsBetween( dt.Subtract( ts ), dt.Add( ts ) );
}

inline wxDateTime wxDateTime::Add( const wxTimeSpan& diff ) const {
  wxASSERT_MSG( IsValid(), wxT( "invalid wxDateTime" ) );
  return wxDateTime( m_time + diff.GetValue() );
}

inline wxDateTime& wxDateTime::Add( const wxTimeSpan& diff ) {
  wxASSERT_MSG( IsValid(), wxT( "invalid wxDateTime" ) );
  m_time += diff.GetValue();
  return *this;
}

inline wxDateTime& wxDateTime::operator+=( const wxTimeSpan& diff ) {
  return Add( diff );
}

inline wxDateTime wxDateTime::Subtract( const wxTimeSpan& diff ) const {
  wxASSERT_MSG( IsValid(), wxT( "invalid wxDateTime" ) );
  return wxDateTime( m_time - diff.GetValue() );
}

inline wxDateTime& wxDateTime::Subtract( const wxTimeSpan& diff ) {
  wxASSERT_MSG( IsValid(), wxT( "invalid wxDateTime" ) );
  m_time -= diff.GetValue();
  return *this;
}

inline wxDateTime& wxDateTime::operator-=( const wxTimeSpan& diff ) {
  return Subtract( diff );
}

inline wxTimeSpan wxDateTime::Subtract( const wxDateTime& datetime ) const {
  wxASSERT_MSG( IsValid() && datetime.IsValid(), wxT( "invalid wxDateTime" ) );
  return wxTimeSpan( GetValue() - datetime.GetValue() );
}

inline wxTimeSpan wxDateTime::operator-( const wxDateTime& dt2 ) const {
  return this->Subtract( dt2 );
}

inline wxDateTime wxDateTime::Add( const wxDateSpan& diff ) const {
  return wxDateTime( *this ).Add( diff );
}

inline wxDateTime& wxDateTime::Subtract( const wxDateSpan& diff ) {
  return Add( diff.Negate() );
}

inline wxDateTime wxDateTime::Subtract( const wxDateSpan& diff ) const {
  return wxDateTime( *this ).Subtract( diff );
}

inline wxDateTime& wxDateTime::operator-=( const wxDateSpan& diff ) {
  return Subtract( diff );
}

inline wxDateTime& wxDateTime::operator+=( const wxDateSpan& diff ) {
  return Add( diff );
}

inline wxDateTime
wxDateTime::ToTimezone( const wxDateTime::TimeZone& tz, bool noDST ) const {
  MODIFY_AND_RETURN( MakeTimezone( tz, noDST ) );
}

inline wxDateTime
wxDateTime::FromTimezone( const wxDateTime::TimeZone& tz, bool noDST ) const {
  MODIFY_AND_RETURN( MakeFromTimezone( tz, noDST ) );
}

inline wxTimeSpan::wxTimeSpan( long hours, long minutes, wxLongLong seconds, wxLongLong milliseconds ) {
  m_diff = hours;
  m_diff *= 60l;
  m_diff += minutes;
  m_diff *= 60l;
  m_diff += seconds;
  m_diff *= 1000l;
  m_diff += milliseconds;
}

inline wxLongLong wxTimeSpan::GetSeconds() const {
  return m_diff / 1000l;
}

inline int wxTimeSpan::GetMinutes() const {
  return ( int )( ( GetSeconds() / 60l ).GetLo() );
}

inline int wxTimeSpan::GetHours() const {
  return GetMinutes() / 60;
}

inline int wxTimeSpan::GetDays() const {
  return GetHours() / 24;
}

inline int wxTimeSpan::GetWeeks() const {
  return GetDays() / 7;
}

inline wxTimeSpan wxTimeSpan::Add( const wxTimeSpan& diff ) const {
  return wxTimeSpan( m_diff + diff.GetValue() );
}

inline wxTimeSpan& wxTimeSpan::Add( const wxTimeSpan& diff ) {
  m_diff += diff.GetValue();
  return *this;
}

inline wxTimeSpan wxTimeSpan::Subtract( const wxTimeSpan& diff ) const {
  return wxTimeSpan( m_diff - diff.GetValue() );
}

inline wxTimeSpan& wxTimeSpan::Subtract( const wxTimeSpan& diff ) {
  m_diff -= diff.GetValue();
  return *this;
}

inline wxTimeSpan& wxTimeSpan::Multiply( int n ) {
  m_diff *= ( long )n;
  return *this;
}

inline wxTimeSpan wxTimeSpan::Multiply( int n ) const {
  return wxTimeSpan( m_diff * ( long )n );
}

inline wxTimeSpan wxTimeSpan::Abs() const {
  return wxTimeSpan( GetValue().Abs() );
}

inline bool wxTimeSpan::IsEqualTo( const wxTimeSpan& ts ) const {
  return GetValue() == ts.GetValue();
}

inline bool wxTimeSpan::IsLongerThan( const wxTimeSpan& ts ) const {
  return GetValue().Abs() > ts.GetValue().Abs();
}

inline wxDateSpan& wxDateSpan::operator+=( const wxDateSpan& other ) {
  m_years += other.m_years;
  m_months += other.m_months;
  m_weeks += other.m_weeks;
  m_days += other.m_days;
  return *this;
}

inline wxDateSpan& wxDateSpan::Add( const wxDateSpan& other ) {
  return *this += other;
}

inline wxDateSpan wxDateSpan::Add( const wxDateSpan& other ) const {
  wxDateSpan ds( *this );
  ds.Add( other );
  return ds;
}

inline wxDateSpan& wxDateSpan::Multiply( int factor ) {
  m_years *= factor;
  m_months *= factor;
  m_weeks *= factor;
  m_days *= factor;
  return *this;
}

inline wxDateSpan wxDateSpan::Multiply( int factor ) const {
  wxDateSpan ds( *this );
  ds.Multiply( factor );
  return ds;
}

inline wxDateSpan wxDateSpan::Negate() const {
  return wxDateSpan( -m_years, -m_months, -m_weeks, -m_days );
}

inline wxDateSpan& wxDateSpan::Neg() {
  m_years = -m_years;
  m_months = -m_months;
  m_weeks = -m_weeks;
  m_days = -m_days;
  return *this;
}

inline wxDateSpan& wxDateSpan::operator-=( const wxDateSpan& other ) {
  return *this += other.Negate();
}

inline wxDateSpan& wxDateSpan::Subtract( const wxDateSpan& other ) {
  return *this -= other;
}

inline wxDateSpan wxDateSpan::Subtract( const wxDateSpan& other ) const {
  wxDateSpan ds( *this );
  ds.Subtract( other );
  return ds;
}

#undef MILLISECONDS_PER_DAY
#undef MODIFY_AND_RETURN

wxTimeSpan operator*( int n, const wxTimeSpan& ts );
wxDateSpan operator*( int n, const wxDateSpan& ds );
void wxNextMonth( wxDateTime::Month& m );
void wxPrevMonth( wxDateTime::Month& m );
void wxNextWDay( wxDateTime::WeekDay& wd );
void wxPrevWDay( wxDateTime::WeekDay& wd );

#endif
